import java.io.DataOutputStream;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

public class JennaKingsburyA3server {

	private static ArrayList<RoutingTableEntry> routingTable = new ArrayList<RoutingTableEntry>();
	private static ArrayList<NetworkNode> dvrMessageElements = new ArrayList<NetworkNode>();
	private static ArrayList<NetworkNode> neighborTable = new ArrayList<NetworkNode>();
	public static ServerSocket server;
	public static BufferedReader inFromClient;
	public static Socket connectionSocket;
	public static String dvrMessage;

	public static void main(String[] args) throws IOException {
		int choice = -1;

		// Initializations
		readInNeighborTable();
		initializeRoutingTable();
		printRoutingTable();

		System.out.println();
		choice = getUserInput();
		System.out.println(dvrMessage + "I think this is the null");

		// We will use this to store the dvrMessage that the client will send
		// us.
		String dvrMessage = null;

		// Create the server's "guidepost" socket. It should share a port with
		// the client socket.
		ServerSocket welcomeSocket = new ServerSocket(33445);
		System.out.println("Voohoo");

		// Set up a specialized socket for communication between the client and
		// the server.
		Socket connectionSocket = welcomeSocket.accept();
		System.out.println("This is Sean's fault");

		BufferedReader inFromClient = new BufferedReader(new InputStreamReader(
				connectionSocket.getInputStream()));

		boolean receivingMessage = true;
		try {
			while (receivingMessage) {
				// Get the message from the client.
				dvrMessage = inFromClient.readLine();
				if (dvrMessage == null) {
					System.out.println("Thanks, Obama.");
					receivingMessage = false;
				} else {
					dvrMessage = dvrMessage.trim();
					System.out
							.println("The DVR Message received from the Client is: "
									+ dvrMessage);
					// Additional Processing here:
					//TODO:
					//Take the message we just got and update our routing table via the algorithm.
					System.out.println("About to process dvrMessage...");
					processDVRMessage(dvrMessage); //Puts the elements of dvrMessage into dvrMessageElements.
					System.out.println("About to update the routing table...");
					updateRoutingTable();
					System.out.println("About to print the routing table...");
					printRoutingTable();
					System.out.println("Routing table printed. Awaiting next message.");
					
				}
			}
		} catch (Exception eRef) {
			// Do nothing! Just hang in there!
		}

		connectionSocket.close();
		welcomeSocket.close();

	}
	
	//Updates the routing table based on the information in dvrMessageElements
	public static void updateRoutingTable() {
		int dest;
		int dist;
		int distToSender = -999999; //Will make any errors obvious; this value should be changed during execution.
		int sender = -1; //Sender is referred to as "N" in the algorithm.
		int C; //Name taken from the algorithm.
		boolean inRoutingTable;
		//for each entry in the message
		for(int i=0; i<dvrMessageElements.size(); i++) {
			dest = dvrMessageElements.get(i).destination;
			dist = dvrMessageElements.get(i).distance;
			
			
			//If we haven't already, Compute distToSender
			if(distToSender == -999999) {
				//C = dist + the weight of the link assigned over which the dvrMessage arrived (which is dest).
				//Scour the neighbor table to find distToSender
				for(int j=0; j < neighborTable.size(); j++) {
					//If we're looking at the correct entry in the neighbor table:
					if(neighborTable.get(j).destination == dvrMessageElements.get(0).destination) {
						distToSender = neighborTable.get(j).distance;
						sender = dest;
						break;
					}//end if
				}//end for
			}//end compute distToSender
			
			C = dist + distToSender;
			
			//Update the routing table
			inRoutingTable = false;//false until proven true;
			
			//Check to see if dest is already in routing table.
			for(int j=0; j<routingTable.size(); j++) {
				if(routingTable.get(j).destination == dest) {
					inRoutingTable = true;
				}//end if
			}//end for
			
			//If the destination is NOT already covered in our routing table
			if(!inRoutingTable) {
				routingTable.add(new RoutingTableEntry(dest, sender, C));
			} else {
				for(int j=0; j < routingTable.size(); j++) {
					if(routingTable.get(j).nextHop == sender) {
						routingTable.get(j).distance = C;
					} else if (routingTable.get(j).distance > C) {
						routingTable.get(j).nextHop = sender;
						routingTable.get(j).distance = C;
					}//end if/else if
				} //end for
			}//end if/else
			
		}//end for
	}//end updateRoutingTable

	public static int getUserInput() {
		int choice = -1;
		Scanner console = new Scanner(System.in);
		System.out.println("Please select an option:");
		System.out.println("1 for Option 1");
		System.out.println("2 for Option 2");
		System.out.println();
		try {
			choice = console.nextInt();
			if (choice != 1 && choice != 2) {
				throw new Exception("Invalid Input.");
			}
		} catch (Exception eRef) {
			System.out.println(eRef.getMessage());
			choice = getUserInput();
		}

		console.close();
		return choice;
	}

	public static void readInNeighborTable() throws IOException {
		File routingData = new File("WT.txt");
		Scanner input = new Scanner(routingData);
		int dest;
		int dist;

		while (input.hasNextInt()) {
			dest = input.nextInt();
			dist = input.nextInt();
			neighborTable.add(new NetworkNode(dest, dist));
		}

		input.close();
	}

	public static void initializeRoutingTable() {
		if (neighborTable.size() > 0) {
			routingTable.add(new RoutingTableEntry(
					neighborTable.get(0).destination, 0, 0));
		}
	}

	public static void printRoutingTable() {
		for (int i = 0; i < routingTable.size(); i++) {
			System.out.println(routingTable.get(i).toString());
		}
	}
	
	public static void processDVRMessage(String message) {
		dvrMessageElements.clear();
		Scanner input = new Scanner(message);
		int dest;
		int dist;

		while (input.hasNextInt()) {
			dest = input.nextInt();
			dist = input.nextInt();
			dvrMessageElements.add(new NetworkNode(dest, dist));
		}

		input.close();
	}
}
